package com.tsfyun.scm.service.impl.order;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Snowflake;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.tsfyun.common.base.enums.TransactionModeEnum;
import com.tsfyun.common.base.enums.domain.MaterielStatusEnum;
import com.tsfyun.common.base.exception.ServiceException;
import com.tsfyun.common.base.util.StringUtils;
import com.tsfyun.common.base.util.TsfPreconditions;
import com.tsfyun.common.base.util.TypeUtils;
import com.tsfyun.scm.base.DataCalling;
import com.tsfyun.scm.dto.finance.ClaimedAmountOrderDTO;
import com.tsfyun.scm.dto.materiel.MaterielDTO;
import com.tsfyun.scm.dto.materiel.MaterielExpDTO;
import com.tsfyun.scm.dto.order.ExpOrderMemberDTO;
import com.tsfyun.scm.dto.order.ExpOrderMemberSaveDTO;
import com.tsfyun.scm.entity.finance.OverseasReceivingOrder;
import com.tsfyun.scm.entity.materiel.MaterielExp;
import com.tsfyun.scm.entity.order.*;
import com.tsfyun.scm.mapper.order.ExpOrderMemberMapper;
import com.tsfyun.scm.service.base.ISystemCacheService;
import com.tsfyun.scm.service.materiel.IMaterielExpService;
import com.tsfyun.scm.service.order.IExpOrderMemberHistoryService;
import com.tsfyun.scm.service.order.IExpOrderMemberService;
import com.tsfyun.common.base.extension.ServiceImpl;
import com.tsfyun.scm.service.order.IImpOrderMemberHistoryService;
import com.tsfyun.scm.system.vo.CountryVO;
import com.tsfyun.scm.system.vo.UnitVO;
import com.tsfyun.scm.util.TsfWeekendSqls;
import com.tsfyun.scm.vo.materiel.MaterielExpVO;
import com.tsfyun.scm.vo.materiel.MaterielVO;
import com.tsfyun.scm.vo.order.ExpOrderMemberVO;
import com.tsfyun.scm.vo.report.ExpOneVoteTheEndVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 出口订单明细 服务实现类
 * </p>
 *
 *
 * @since 2021-01-26
 */
@Service
public class ExpOrderMemberServiceImpl extends ServiceImpl<ExpOrderMember> implements IExpOrderMemberService {

    @Resource
    private Snowflake snowflake;

    @Autowired
    private ExpOrderMemberMapper expOrderMemberMapper;

    @Autowired
    private IExpOrderMemberHistoryService expOrderMemberHistoryService;

    @Autowired
    private ISystemCacheService systemCacheService;

    @Autowired
    private IMaterielExpService materielExpService;

    @Override
    public List<ExpOrderMember> getByExpOrderId(Long expOrderId){
        return expOrderMemberMapper.selectByExample(Example.builder(ExpOrderMember.class).where(TsfWeekendSqls.<ExpOrderMember>custom()
                .andEqualTo(false,ExpOrderMember::getExpOrderId,expOrderId)).build());
    }

    @Override
    public List<ExpOrderMemberVO> findOrderMaterielMember(Long expOrderId) {
        return expOrderMemberMapper.findOrderMaterielMember(expOrderId);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removeByExpOrderId(Long orderId) {
        expOrderMemberMapper.deleteByExample(Example.builder(ExpOrderMember.class).where(TsfWeekendSqls.<ExpOrderMember>custom().andEqualTo(false,ExpOrderMember::getExpOrderId,orderId)).build());
    }

    @Override
    public ExpOrderMemberSaveDTO checkWrapOrderMember(ExpOrder order, List<ExpOrderMemberDTO> paramMembers, Boolean submitAudit) {
        //订单数据合计
        order.setTotalPrice(BigDecimal.ZERO);//委托金额
        order.setDecTotalPrice(BigDecimal.ZERO);//报关金额
        order.setTotalCartonNum(0);//总箱数
        order.setTotalMember(paramMembers.size());//产品条数
        order.setTotalNetWeight(BigDecimal.ZERO);//总净重
        order.setTotalCrossWeight(BigDecimal.ZERO);//总毛重

        List<ExpOrderMember> saveOrderMembers = Lists.newArrayList();
        Map<Long,ExpOrderMember> orderMemberMap = new ConcurrentHashMap<>();
        if(Objects.nonNull(order.getId())) {
            //修改订单查询订单原始明细数据
            List<ExpOrderMember> oldExpOrderMembers = getByExpOrderId(order.getId());
            if(CollUtil.isNotEmpty(oldExpOrderMembers)) {
                orderMemberMap = oldExpOrderMembers.stream().collect(Collectors.toMap(ExpOrderMember::getId, Function.identity()));
            }
        }
        Map<String, UnitVO> unitVOMap = Maps.newHashMap();
        if(CollUtil.isNotEmpty(paramMembers)) {
            for(int i = 0,length = paramMembers.size(); i < length; i++) {
                final Integer rowNo = i + 1;
                ExpOrderMemberDTO expOrderMemberDTO = paramMembers.get(i);
                //如果是新增订单，则订单明细id置空防止误判
                if(Objects.isNull(order.getId())) {
                    expOrderMemberDTO.setId(null);
                }
                ExpOrderMember expOrderMember;
                if(Objects.isNull(expOrderMemberDTO.getId())) {
                    expOrderMember = new ExpOrderMember();
                } else {
                    expOrderMember = orderMemberMap.get(expOrderMemberDTO.getId());
                    TsfPreconditions.checkArgument(Objects.nonNull(expOrderMember),new ServiceException(String.format("第%d行订单明细数据不存在，请删除该明细重新填写",rowNo)));
                    //数据库存在且用户也提交过来的排除掉
                    orderMemberMap.remove(expOrderMemberDTO.getId());
                }
                expOrderMember.setGoodsCode(StringUtils.isNotEmpty(expOrderMemberDTO.getGoodsCode())?expOrderMemberDTO.getGoodsCode():"");
                //型号
                expOrderMember.setModel(expOrderMemberDTO.getModel());
                //品牌
                expOrderMember.setBrand(expOrderMemberDTO.getBrand());
                //品名
                expOrderMember.setName(expOrderMemberDTO.getName());
                //验货前端不需要更改
                if(expOrderMemberDTO.getSpec()!=null){
                    //规格参数
                    expOrderMember.setSpec(expOrderMemberDTO.getSpec());
                }
                //客户物料号
                expOrderMember.setGoodsCode(expOrderMemberDTO.getGoodsCode());
                //数量
                expOrderMember.setQuantity(StringUtils.rounded2(TypeUtils.castToBigDecimal(expOrderMemberDTO.getQuantity(), BigDecimal.ZERO)));
                //总价
                expOrderMember.setTotalPrice(StringUtils.rounded2(TypeUtils.castToBigDecimal(expOrderMemberDTO.getTotalPrice(), BigDecimal.ZERO)));
                //净重
                expOrderMember.setNetWeight(StringUtils.rounded4(TypeUtils.castToBigDecimal(expOrderMemberDTO.getNetWeight(), BigDecimal.ZERO)));
                //毛重
                expOrderMember.setGrossWeight(StringUtils.rounded4(TypeUtils.castToBigDecimal(expOrderMemberDTO.getGrossWeight(), BigDecimal.ZERO)));
                //箱数
                expOrderMember.setCartonNum(TypeUtils.castToInt(expOrderMemberDTO.getCartonNum(),0));
                //箱号(修改订单前端未传，空字符串允许保存)
                if(expOrderMemberDTO.getCartonNo()!=null){
                    expOrderMember.setCartonNo(expOrderMemberDTO.getCartonNo());
                }
                //单价
                expOrderMember.setUnitPrice(expOrderMember.getQuantity().compareTo(BigDecimal.ZERO) == 1 ?
                        StringUtils.rounded4(expOrderMember.getTotalPrice().divide(expOrderMember.getQuantity(),4,BigDecimal.ROUND_HALF_UP))
                        : BigDecimal.ZERO);

                //校验单位
                if(StringUtils.isNotEmpty(expOrderMemberDTO.getUnitName())){
                    UnitVO unitVO = unitVOMap.get(expOrderMemberDTO.getUnitName());
                    if(Objects.isNull(unitVO)) {
                        unitVO = systemCacheService.getUnitByName(expOrderMemberDTO.getUnitName());
                        Optional.ofNullable(unitVO).orElseThrow(()->new ServiceException(String.format("订单明细第%d行单位错误",rowNo)));
                    }
                    expOrderMember.setUnitCode(unitVO.getId());
                    expOrderMember.setUnitName(unitVO.getName());
                    unitVOMap.put(expOrderMemberDTO.getUnitName(),unitVO);
                }

                //原产国(地区)
                expOrderMember.setCountry("CHN");
                expOrderMember.setCountryName("中国");

                expOrderMember.setDecTotalPrice(expOrderMember.getTotalPrice());
                expOrderMember.setDecUnitPrice(expOrderMember.getUnitPrice());

                order.setTotalPrice(order.getTotalPrice().add(expOrderMember.getTotalPrice()).setScale(2,BigDecimal.ROUND_HALF_UP));
                order.setDecTotalPrice(order.getDecTotalPrice().add(expOrderMember.getDecTotalPrice()).setScale(2,BigDecimal.ROUND_HALF_UP));
                order.setTotalCartonNum(order.getTotalCartonNum()+expOrderMember.getCartonNum());
                order.setTotalNetWeight(order.getTotalNetWeight().add(expOrderMember.getNetWeight()).setScale(4,BigDecimal.ROUND_HALF_UP));
                order.setTotalCrossWeight(order.getTotalCrossWeight().add(expOrderMember.getGrossWeight()).setScale(4,BigDecimal.ROUND_HALF_UP));
                saveOrderMembers.add(expOrderMember);
            }
        }
        if(order.getTotalNetWeight().compareTo(order.getTotalCrossWeight())==1){
            throw new ServiceException("总净重不能大于总毛重");
        }
        return new ExpOrderMemberSaveDTO(saveOrderMembers,orderMemberMap.values().stream().collect(Collectors.toList()));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer saveMembers(ExpOrder expOrder, ExpOrderMemberSaveDTO expOrderMemberSaveDTO, Boolean isSubmit) {
        Integer newSize = 0;//新增物料数
        //删除订单原始明细数据
        expOrderMemberHistoryService.removeByOrderId(expOrder.getId());
        //需要删除的订单明细
        List<ExpOrderMember> deleteOrderMembers = expOrderMemberSaveDTO.getDeleteOrderMembers();
        if(CollUtil.isNotEmpty(deleteOrderMembers)){
            List<Long> orderMemberIds = deleteOrderMembers.stream().map(ExpOrderMember::getId).collect(Collectors.toList());
            List<String> materialIds = deleteOrderMembers.stream().filter(r-> StringUtils.isNotEmpty(r.getMaterialId())).map(ExpOrderMember::getMaterialId).collect(Collectors.toList());
            //删除明细
            super.removeByIds(orderMemberIds);
            //删除物料
            materielExpService.removeIdsNotPrompt(materialIds);
        }
        List<ExpOrderMember> expOrderMembers = expOrderMemberSaveDTO.getSaveOrderMembers();
        if(CollUtil.isNotEmpty(expOrderMembers)) {
            for(int i = 0,length = expOrderMembers.size();i < length;i++) {
                expOrderMembers.get(i).setRowNo(i + 1);
                if(Objects.isNull(expOrderMembers.get(i).getId())){
                    expOrderMembers.get(i).setId(snowflake.nextId());
                    expOrderMembers.get(i).setExpOrderId(expOrder.getId());
                }
                if(StringUtils.isEmpty(expOrderMembers.get(i).getModel())){
                    expOrderMembers.get(i).setModel("无");
                }
                if(StringUtils.isEmpty(expOrderMembers.get(i).getBrand())){
                    expOrderMembers.get(i).setBrand("无");
                }
//                expOrderMembers.get(i).setModel(expOrderMembers.get(i).getModel().replace("型号","").replace("型",""));
//                expOrderMembers.get(i).setBrand(expOrderMembers.get(i).getBrand().replace("品牌","").replace("牌","").toUpperCase());
                if(isSubmit){
                    MaterielExpDTO dto = new MaterielExpDTO();
                    dto.setCustomerId(expOrder.getCustomerId());
                    dto.setCode(expOrderMembers.get(i).getGoodsCode());
                    dto.setModel(expOrderMembers.get(i).getModel());
                    dto.setBrand(expOrderMembers.get(i).getBrand());
                    dto.setName(expOrderMembers.get(i).getName());
                    dto.setSpec(expOrderMembers.get(i).getSpec());
                    dto.setSource("出口订单："+expOrder.getDocNo());
                    dto.setSourceMark(expOrder.getDocNo());
                    MaterielExpVO materielVO = materielExpService.obtainMaterialAndSave(dto);
                    if(Objects.equals(MaterielStatusEnum.WAIT_CLASSIFY,MaterielStatusEnum.of(materielVO.getStatusId()))){
                        newSize++;
                    }
                    expOrderMembers.get(i).setMaterialId(materielVO.getId());
                }
            }
            expOrderMemberMapper.savaAndUpdateBatch(expOrderMembers);

            //记录原始数据
            List<ExpOrderMemberHistory> historyList = beanMapper.mapAsList(expOrderMembers,ExpOrderMemberHistory.class);
            expOrderMemberHistoryService.savaBatch(historyList);
        }
        return newSize;
    }

    @Override
    public List<ExpOrderMember> getByOrderId(Long expOrderId) {
        TsfWeekendSqls wheres = TsfWeekendSqls.<ExpOrderMember>custom().andEqualTo(false,ExpOrderMember::getExpOrderId,expOrderId);
        List<ExpOrderMember> expOrderMembers = expOrderMemberMapper.selectByExample(Example.builder(ExpOrderMember.class).where(wheres).build());
        if(CollUtil.isNotEmpty(expOrderMembers)){
            //按行号升序
            return expOrderMembers.stream().sorted(Comparator.comparing(ExpOrderMember::getRowNo)).collect(Collectors.toList());
        }
        return new ArrayList<>();
    }

    @Override
    public List<PriceFluctuationHistoryExp> findExpHistory(LocalDateTime dateTime, String model, String brand, String name, String spec) {
        return expOrderMemberMapper.findExpHistory(dateTime, model, brand, name, spec);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateMemberMaterielId(String oldId, String newId) {
        expOrderMemberMapper.updateMemberMaterielId(oldId,newId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchUpdatePartData(List<ExpOrderMember> expOrderMemberList) {
        expOrderMemberList.stream().forEach(iom->{
            updateByIdSelective(iom);
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void overseasAccountClaimed(ClaimedAmountOrderDTO dto) {
        BigDecimal unclaimedValue = dto.getUnclaimedValue();
        List<ExpOrderMember> memberList = getByExpOrderId(dto.getOrderId());
        for(ExpOrderMember member : memberList){
            if(unclaimedValue.compareTo(BigDecimal.ZERO) == 0){
                break;
            }
            BigDecimal surplus = member.getDecTotalPrice().subtract(member.getAmountCollected()).setScale(2,BigDecimal.ROUND_HALF_UP);
            if(surplus.compareTo(BigDecimal.ZERO) == 1){
                // 此条明细可认领金额大于等于总认领金额
                if(surplus.compareTo(unclaimedValue) == 1){
                    member.setAmountCollected(member.getAmountCollected().add(unclaimedValue).setScale(2,BigDecimal.ROUND_HALF_UP));
                    unclaimedValue = BigDecimal.ZERO;
                }else{
                    member.setAmountCollected(member.getAmountCollected().add(surplus).setScale(2,BigDecimal.ROUND_HALF_UP));
                    unclaimedValue = unclaimedValue.subtract(surplus).setScale(2,BigDecimal.ROUND_HALF_UP);
                }
                super.updateById(member);
            }
        }
        if(unclaimedValue.compareTo(BigDecimal.ZERO) != 0){
            throw new ServiceException(String.format("订单【%s】明细认领金额错误",dto.getOrderNo()));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void clearClaimOrder(OverseasReceivingOrder receivingOrder) {
        BigDecimal clearValue = receivingOrder.getAccountValue();
        List<ExpOrderMember> memberList = getByExpOrderId(receivingOrder.getExpOrderId());
        for(ExpOrderMember member : memberList){
            if(clearValue.compareTo(BigDecimal.ZERO) == 0){
                break;
            }
            if(member.getAmountCollected().compareTo(BigDecimal.ZERO) == 1){
                if(member.getAmountCollected().compareTo(clearValue) == 1){
                    // 此条明细取消金额大于等于总取消金额
                    member.setAmountCollected(member.getAmountCollected().subtract(clearValue).setScale(2,BigDecimal.ROUND_HALF_UP));
                    clearValue  = BigDecimal.ZERO;
                }else{
                    clearValue = clearValue.subtract(member.getAmountCollected()).setScale(2,BigDecimal.ROUND_HALF_UP);
                    member.setAmountCollected(BigDecimal.ZERO);
                }
                super.updateById(member);
            }
        }
        if(clearValue.compareTo(BigDecimal.ZERO) != 0){
            throw new ServiceException(String.format("订单【%s】明细认领金额错误",receivingOrder.getOrderNo()));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer saveInspectionMembers(ExpOrder expOrder, List<ExpOrderMember> expOrderMembers) {
        Integer newSize = 0;
        for(int i = 0,length = expOrderMembers.size();i < length;i++) {
            expOrderMembers.get(i).setRowNo(i + 1);
            MaterielExpDTO dto = new MaterielExpDTO();
            dto.setCustomerId(expOrder.getCustomerId());
            dto.setModel(expOrderMembers.get(i).getModel());
            dto.setBrand(expOrderMembers.get(i).getBrand());
            dto.setName(expOrderMembers.get(i).getName());
            dto.setSpec(expOrderMembers.get(i).getSpec());
            dto.setSource("出口订单："+expOrder.getDocNo());
            dto.setSourceMark(expOrder.getDocNo());
            MaterielExpVO materielVO = materielExpService.obtainMaterialAndSave(dto);
            if(Objects.equals(MaterielStatusEnum.WAIT_CLASSIFY,MaterielStatusEnum.of(materielVO.getStatusId()))){
                newSize++;
            }
            expOrderMembers.get(i).setMaterialId(materielVO.getId());
        }
        expOrderMemberMapper.savaAndUpdateBatch(expOrderMembers);
        return newSize;
    }

    @Override
    public List<ExpOneVoteTheEndVO> oneVoteTheEndByOrderId(Long orderId) {
        return expOrderMemberMapper.oneVoteTheEndByOrderId(orderId);
    }

    @Override
    public BigDecimal getOrderQuantity(String orderNo) {
        return expOrderMemberMapper.getOrderQuantity(orderNo);
    }
}
